#!/usr/bin/python

"""
/* main.py - sudoku puzzle UI game
 *
 * Copyright 2009
 * Authored by Erin Yueh <erinyueh@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 */
""" 
 
import cgi
import os

from datetime import datetime, date, time
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db
from google.appengine.ext.webapp import template

import xml.etree.cElementTree as etree
import facebook
from facebook import FacebookError

## API Keys go here!
_FbApiKey = 'YOUR API KEY'
_FbSecret = 'YOUR AP SECRET KEY'

class GameScore(db.Model):
  player = db.StringProperty()
  date = db.DateProperty(auto_now_add=True)
  score = db.IntegerProperty()
  level = db.StringProperty()
  show = db.BooleanProperty()
  content = db.StringProperty(multiline=True)
  name = db.StringProperty()
  photo = db.LinkProperty()
  profile = db.LinkProperty()
  
class Upload(webapp.RequestHandler):

  def post(self):

    fb = facebook.Facebook(_FbApiKey, _FbSecret)
    fb.session_key = self.request.get('session_key')
    fb.uid = self.request.get('uid')

    key_name = self.request.get('key')
    lastrec = db.get(db.Key(key_name))
    lastrec.show = True
    today = lastrec.date 
    level = lastrec.level
    lastrec.content = self.request.get('content')
    db.put(lastrec)
    # retrieve today top ten records only
    q = db.GqlQuery("SELECT * FROM GameScore " + 
                "WHERE date = :1 AND level = :2 " +
                "ORDER BY score ",
                today,level)
    result = q.fetch(10)

    phtmldata = "<table align='center' style='border-style=none;' width='70%'>" 

    for score in result:
        img = "" 
        if score.profile != score.photo:
            img = "<img width='50' height='50' src='" + score.photo + "'>"
        profile_link = "<a href='" + score.profile + "'>" + score.name + "</a>"
        minute = int(score.score) / 60
        sec = int(score.score) % 60 
        spent_time = str(minute) + "min " + str(sec) + " sec"
        phtmldata += "<tr><td >" + img + "</td><td>" + profile_link + "</td><td class='score_name'>" + spent_time + "</td><td width='40%' class='score_name'>" + score.content + "</td></tr>"
    
    phtmldata += "</table>\n"   
    
    link = "<a href='http://todaysudoku.appspot.com'>Back</a>"
    template_values = {
      'scores': result,
      'phtmldata': phtmldata,
      'level': level,
      'today': today,
      'link':link,
      }

    path = os.path.join(os.path.dirname(__file__), 'score.html')
    self.response.out.write(template.render(path, template_values))
      
class Solve(webapp.RequestHandler):

  def post(self):

    params = self.request.params
    isOK = self.checkPuzzleData(params)

    fb = facebook.Facebook(_FbApiKey, _FbSecret)
    fb.session_key = self.request.get('session_key')
    fb.uid = self.request.get('uid')
    info = fb.users.getInfo([fb.uid],['name','pic','profile_url'])
    user = info[0]
    player_name = str(user['name'])

    if isOK is False:
       url = fb.get_add_url()
       self.response.out.write('<script language="javascript"> alert("Wrong! Not Completed!")</script>')
       self.response.out.write('<script language="javascript">top.location.href="' + url + '"</script>')
       return
    
    spendtime = str(self.request.get("timespent"))  
    minute = spendtime[:-3]
    sec = spendtime[-2:]
    count = int(minute) * 60 + int(sec)

    # write score to db
    score = GameScore()
    score.player = str(fb.uid)
    score.name = str(user['name'])
    if user['pic']:
        score.photo = user['pic']
    else:
        score.photo = user['profile_url']
    score.profile = user['profile_url']
    score.level = self.request.get('level')
    score.score = count
    score.content = ""      
    score.show = False
    score.put()
    key = score.key()

    template_values = {
      'level': score.level,
      'score': spendtime,  
      'uid':fb.uid,
      'player_name':player_name,
      'session_key':fb.session_key,
      'key':key,
      }

    path = os.path.join(os.path.dirname(__file__), 'result.html')
    self.response.out.write(template.render(path, template_values))

  def checkPuzzleData(self,params):
  
    isOK = True
    puzzle = []
    for i in xrange(9):
        row = [0,0,0,0,0,0,0,0,0]
        puzzle.append(row)
    
    for i in xrange (9):
        for j in xrange(9):
            addr = i *9 + j
            name = "cell" + str(addr)
            value = params.get(name)
            if value is not "":
                puzzle[i][j] = value
            if value == "":
                puzzle[i][j] = 0
    
    row =  [ [] for i in xrange(9)]
    column =  [ [] for i in xrange(9)]
    group =  [ [] for i in xrange(9)]
    for i in xrange (9):
        for j in xrange(9):
            value = int(puzzle[i][j])
            g = (i/3)*3 + (j/3)
            row[i].append(value)
            column[j].append(value)
            group[g].append(value)
    
    # should only display once
    for x in xrange(9):
        for v in xrange(1,10):
            if not(row[x].count(v) == 1 and column[x].count(v) ==1 and group[x].count(v) ==1):
                isOK = False
     
    return isOK 
    

class NewPuzzle(webapp.RequestHandler):

  def post(self):

    level = self.request.get('level')
    auth_token = self.request.get('auth_token')
    session_key = self.request.get('session_key')
    uid = self.request.get('uid')

    current_date = datetime.now().date()
    first_date = date(2009,1,1)
    dist = abs(current_date-first_date).days

    level = self.request.get('level')
    if level == "":
        level = "easy"

    (easy_selected, medium_selected, hard_selected) = ("","","")
    if level == "easy":    
        easy_selected = "selected"
    elif level =="medium":
        medium_selected = "selected"
    elif level =="hard":
        hard_selected = "selected"        

    today_puzzle = "puzzle/1000_" + str(level)
    pname = os.path.join(os.path.dirname(__file__), today_puzzle)
    puzzle = ""
    if (open(pname,'r')):
        f = open(pname,'r')
        buf = f.readlines()
        f.close()  
        # will pick one by date 
        puzzle = buf[dist%1000]

    phtmldata = "<table CELLSPACING='0' align='center'>\n"    
    # make a html table
    for i in xrange (9):
        if i == 3 or i ==6:
            phtmldata += "<TR class='hline' id=row" + str(i+1) + ">\n"
        else:
            phtmldata += "<TR id=row" + str(i+1) + ">\n"

        for j in xrange(9):
            addr = i *9 + j
            cell_class = ""
            if int(puzzle[addr]) == 0:
                value = " value ='' "
                cell_class = "cell_input"
            else:
                value = " value ='"+ str(puzzle[addr]) + "' readonly"
                cell_class = "cell_value"
            if j == 2 or j ==5:
                phtmldata += "<TD class ='cell vline'><input class='"+ cell_class+"' autocomplete='off' size='2' maxlength='1' name=cell"+ str(addr) + str(value) +"> </TD>\n"
            else:    
                phtmldata += "<TD class ='cell'><input class='"+ cell_class+"' autocomplete='off' size='2' maxlength='1' name=cell"+ str(addr) + str(value) +"> </TD>\n"
        phtmldata += "</TR>\n"
    phtmldata += "</table>\n"    

    template_values = {
      'easy_selected': easy_selected,
      'medium_selected': medium_selected,
      'hard_selected': hard_selected,
      'uid':uid,
      'level':level,
      'today':current_date,
      'session_key':session_key,
      'auth_token':auth_token,
      'puzzle':phtmldata,
      }

    path = os.path.join(os.path.dirname(__file__), 'index.html')
    self.response.out.write(template.render(path, template_values))

class MainPage(webapp.RequestHandler):

  def get(self):

    ## instantiate the Facebook API wrapper with your FB App's keys
    fb = facebook.Facebook(_FbApiKey, _FbSecret)
    auth_token = self.request.get('auth_token')

    if not fb.check_session(self.request) or not auth_token:
        url = fb.get_login_url()
        self.response.out.write('<script language="javascript">top.location.href="' + url + '"</script>')
        return

    session_key = self.request.get('fb_sig_session_key')
    uid = self.request.get('fb_sig_user')

    self.response.out.write('<html><head>')
    self.response.out.write('<script src="/static/js/timer.js" type="text/javascript" charset="utf-8"></script></head>')
    self.response.out.write('<body onload="submit()">')
    self.response.out.write('<form action="/New" method="post" name="puzzle_level">')
    self.response.out.write('<input type="hidden" name="session_key" value="%s"> ' % session_key)
    self.response.out.write('<input type="hidden" name="level" value="easy">')
    self.response.out.write('<input type="hidden" name="uid" value="%s">' % uid)
    self.response.out.write('<input type="hidden" name="auth_token" value="%s"> ' % auth_token)
    self.response.out.write('</form></body></html>')

application = webapp.WSGIApplication(
                                     [('/', MainPage),
                                     ('/New', NewPuzzle),
                                     ('/Upload', Upload), 
                                      ('/Solve', Solve)],                                     
                                     debug=True)

def main():
  run_wsgi_app(application)

if __name__ == "__main__":
  main()
